/**
 * 
 */
package com.williamoneil.charts.client.data;

import java.util.Date;
import java.util.List;

import com.williamoneil.charts.client.util.CalendarUtil;
import com.williamoneil.charts.client.util.ChartUtil;
import com.williamoneil.charts.shared.PeriodicityType;

/**
 * @author Gudipati
 *
 */
public class DateAxis {

	private Date firstDate = null;
	private Date lastDate = null; 
	
	private List<Tick> ticks = null;
	//private Date chartEndDate = null;
	private PeriodicityType periodicity = null;
	
	private ChartBoundsRect bounds = null;
	private int tickSpacing = ChartUtil.DEFAULT_TICK_SPACING;
	
	public DateAxis(final ChartBoundsRect bounds, final List<Tick> ticks, final PeriodicityType period, final int tickSpacing) {
		this.bounds = bounds;
		this.periodicity = period;
		this.ticks = ticks;
		this.tickSpacing  = tickSpacing;
		
		// get the first and last dates in the p-v list
		firstDate = ticks.get(ticks.size() - 1).getDate();
		lastDate = ticks.get(0).getDate();
	}
	
	public Date getChartDate(final int x) {
		final Tick tick = getTickAtX(x);
		if(tick != null) {
			return tick.getDate();
		}
		return null;
	}

	public Tick getTickAtX(int x) {
		if(x < bounds.getX()) {
			return null;
		}
		
		int tickOffSet = Math.round((bounds.getWidthWithoutScale() - x)/ tickSpacing);
		
		if(tickOffSet < 0) {
			tickOffSet = 0;
		} else if (tickOffSet >= ticks.size()) {
			tickOffSet = ticks.size()-1;
		}
		
		return ticks.get(tickOffSet);		
	}
	
	public int getX(Date date) {
		final int numOfTicksFromLast = getTickIndex(date);
		if(numOfTicksFromLast < 0) {
			return -1;
		}
		return bounds.getWidthWithoutScale() - (numOfTicksFromLast * tickSpacing);
	}
	
	public int getTickIndex(final Date date) {
		if(date == null) {
			return -1;
		}
		
		Date finalDate = date;
		if(periodicity == PeriodicityType.Weekly) {
			finalDate = CalendarUtil.toFridaySameWeek(date);
		} else if (periodicity == PeriodicityType.Monthly) {
			finalDate = CalendarUtil.toLastDaySameMonth(date);
		}
				
		switch(periodicity) {
		case Daily: {
			final int daysDiffFromFirst = CalendarUtil.daysDiff(finalDate, firstDate);
			final int daysDiffFromLast = CalendarUtil.daysDiff(lastDate, finalDate);

			// check if date is within our range
			if(daysDiffFromFirst < 0 || daysDiffFromLast < 0) {
				return -1;
			}
			
			return CalendarUtil.weekDaysDiff(lastDate, finalDate);
		}
		case Weekly: {
			return CalendarUtil.weeksDiff(lastDate, finalDate);
		}
		case Monthly: {
			return CalendarUtil.monthsDiff(lastDate, finalDate);
		}
		}
		return -1;
	}
	
}
